#include "StdAfx.h"
#include "GameIO.h"

// static variables
IDirectInput8* GameIO::diCOM = NULL;


/******************************************************************
Purpose: initialized the IO (keyboard and a mouse)
Descripton: 
Return:
******************************************************************/
GameIO::GameIO(HINSTANCE hinstance, HWND hwnd): mKeyboardDev(NULL), mMouseDev(NULL)
{
	int rc = 0;
	if (this->diCOM == NULL) {
		// initialize the com interface
		rc = DirectInput8Create(hinstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&diCOM, NULL);
		
		// error
		if (rc != DI_OK) diCOM = NULL;
	}

	// initialize the keyboard
	rc = initKeyboard(hwnd, DISCL_NONEXCLUSIVE|DISCL_FOREGROUND);
	if (rc != 0) mKeyboardDev = NULL;


	// initialize the mouse
	rc = initMouse(hwnd, DISCL_NONEXCLUSIVE|DISCL_FOREGROUND);
	if (rc != 0) mMouseDev = NULL;

}


/******************************************************************
Purpose: release the resources
Descripton: 
Return:
******************************************************************/
GameIO::~GameIO(void)
{
	if (mKeyboardDev != NULL)
	{
		mKeyboardDev->Unacquire();
		mKeyboardDev->Release();
		mKeyboardDev = NULL;
	}

	if (mMouseDev != NULL)
	{
		mMouseDev->Unacquire();
		mMouseDev->Release();
		mMouseDev = NULL;
	}

	if (diCOM != NULL)
	{
		diCOM->Release();
		diCOM = NULL;
	}
}


/******************************************************************
Purpose: initializes the keyboard
Descripton: 
Return:0 if OK, 1 if error
******************************************************************/
int GameIO::initKeyboard(HWND hwnd, long CooperativeFlags)
{

	if (diCOM == NULL) return(1);	// error

	// get the device
	diCOM->CreateDevice(GUID_SysKeyboard, &mKeyboardDev, NULL);
	if (mKeyboardDev == NULL) {
		return(1);
	}

	// set the coopertive flags
	mKeyboardDev->SetCooperativeLevel(hwnd, CooperativeFlags);

	// set the keyboard status strucure
	ZeroMemory(m_KeyboardState, sizeof(char) * 256);
	mKeyboardDev->SetDataFormat(&c_dfDIKeyboard);

	// acquire the keyboard
	mKeyboardDev->Acquire();

	return(0);
}


/******************************************************************
Purpose: initializes the mouse device
Descripton: 
Return:0 if OK, 1 if error
******************************************************************/
int GameIO::initMouse(HWND hwnd, long CooperativeFlags)
{
	if (diCOM == NULL) return(1);	// error

	// get the device
	diCOM->CreateDevice(GUID_SysMouse, &mMouseDev, NULL);
	if (mMouseDev == NULL) {
		return(1);
	}

	// set the coopertive flags
	mMouseDev->SetCooperativeLevel(hwnd, CooperativeFlags);

	// set the keyboard status strucure
	ZeroMemory(&mMouseState, sizeof(DIMOUSESTATE));
	mMouseDev->SetDataFormat(&c_dfDIMouse); // set the data format

	// acquire the keyboard
	mMouseDev->Acquire();

	return(0);
}


/******************************************************************
Purpose: get the state of the keyboard and mouse
Descripton: Note: should be devided into three functions.
Return: 0=OK, 1=could not get data try again, -1=error with device
******************************************************************/
int GameIO::poll(void)
{
	int rc = 0;
	int count; 

	// get the keyboard state
	rc = mKeyboardDev->GetDeviceState(256, m_KeyboardState);
	count = 0;
	while (rc != DI_OK) {
		switch (rc) {
			case DI_OK: 
				break;
			case DIERR_INPUTLOST:
			case DIERR_NOTACQUIRED:
				mKeyboardDev->Acquire();
				break;
			case E_PENDING:
				break;
			case DIERR_INVALIDPARAM:
			case DIERR_NOTINITIALIZED:
			default:
				// error has occured
				return(-1);
		}
		rc = mKeyboardDev->GetDeviceState(256, m_KeyboardState);
		count++;
		if (count > 100) return(1);
	}
	
	// get the mouse state
	count = 0;
	rc = mMouseDev->GetDeviceState(sizeof(DIMOUSESTATE), &mMouseState);
	count = 0;
	while (rc != DI_OK) {
		switch (rc) {
			case DI_OK: 
				break;
			case DIERR_INPUTLOST:
			case DIERR_NOTACQUIRED:
				mMouseDev->Acquire();
				break;
			case E_PENDING:
				break;
			case DIERR_INVALIDPARAM:
			case DIERR_NOTINITIALIZED:
			default:
				// error has occured
				return(-1);
		}
		rc = mMouseDev->GetDeviceState(sizeof(DIMOUSESTATE), &mMouseState);
		count++;
		if (count > 100) return(1);
	}
	return 0;
}


/******************************************************************
Purpose: returns the change along the x coordinate
Descripton:
Return: 
******************************************************************/
int GameIO::mouseDX(void) { return(mMouseState.lX); }


/******************************************************************
Purpose: returns the change along the y coordinate
Descripton:
Return: 
******************************************************************/
int GameIO::mouseDY(void) { return(mMouseState.lY); }


/******************************************************************
Purpose: returns the change along the z coordinate
Descripton:
Return: 
******************************************************************/
int GameIO::mouseDZ(void) { return(mMouseState.lZ); }


/******************************************************************
Purpose: returns a vector of the mouse move
Descripton:
Return: 
******************************************************************/
D3DXVECTOR3 GameIO::mouseDelta(void) { return D3DXVECTOR3((float)mMouseState.lX,(float)mMouseState.lY,(float)mMouseState.lZ); }


/******************************************************************
Purpose: checks if a specific mouse button was pressed
Descripton: check if a given mouse button was pressed
Return: 1 - if pressed, 0 - if not pressed
******************************************************************/
int GameIO::mouseButtonPressed(int button) { return(mMouseState.rgbButtons[button] & 0x80); }


/******************************************************************
Purpose: checks if a specific keyboard key was pressed
Descripton: 
Return: true - if pressed, false - if not pressed
******************************************************************/
bool GameIO::keyDown(char key) { return(m_KeyboardState[key] & 0x80) ? true : false; }

